﻿//////////////////////////////////////////////////////////////////////////////////
//
// ActionScript 3.0 Common Library (MIT License)
// Copyright (c) 2009 AS3CommonCode | Tony Birleffi | http://www.mosaiceye.com
// 
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////////

package org.as3commoncode.net.loader
{
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.events.ProgressEvent;
    import org.as3commoncode.net.loader.AbstractLoader;
	
	/**
	 * A queue loader class that manages a queue of many loaders.
	 * 
	 * @example
	 * <listing>
	 * var vQueueLoader:QueueLoader = new QueueLoader();
	 * vQueueLoader.addEventListener(Event.COMPLETE, onLoadComplete);
	 * vQueueLoader.addLoader(vLoader);
	 * vQueueLoader.start();
	 * </listing>
	 * 
	 * @see flash.events.EventDispatcher;
	 * 
	 * @author Tony Birleffi
	 */
    public class QueueLoader extends EventDispatcher
	{
		/** Holds all the loader references. */
        protected var queue:Array;
		
		/** Current index. */
        protected var active:Number;
		
		/** If the loader is running or not. */
        private var run:Boolean;
		
		/**
         * Handles the initial setup.
         */
		public function QueueLoader() 
		{
            super();
            this.queue = new Array();
        }

        /**
         * Starts to download the queue.
         */
        public function start():void 
		{
            this.active = 0;
            loadStart();
            loadNext();
        }

        /**
         * Adds a loader to the queue.
         * 
		 * @param loader		each loader.
         */
        public function addLoader(loader:AbstractLoader):void 
		{
            if(loader != null) queue.push(loader);
        }

        /**
         * Removes all loaders from the queue.
         */
        public function removeLoaders():void 
		{
            this.queue = new Array();
        }

        /**
         * Stops the loaders.
         */
        public function stop():void 
		{
			// If the queue is running.
            if(running)
			{
				// Instance of each loader.
                var loader:AbstractLoader = AbstractLoader(this.queue[ this.active - 1 ]);
				
				// If the current loader is not null then stop the queue loader.
                if(loader != null) 
				{
					// Remove the listener.
                    loader.removeEventListener(Event.COMPLETE, onLoaded);
					
					// Stop the current load.
                    loader.stop();
                }
            }
        }
		
		/**
         * Catches the event from a loader when its finished with loading.
		 * @param event			the loader event.
         */
        private function onLoaded(event:Event):void 
		{
			// Instance of the current loader.
            var loader:AbstractLoader = AbstractLoader(event.target);
			
			// Remove the listener.
            loader.removeEventListener(Event.COMPLETE, onLoaded);
			
			// Dispatch out the queues current progress.
            dispatchEvent(new ProgressEvent(ProgressEvent.PROGRESS, false, false, this.active, this.queue.length));
			
           	// Increment.
           	this.active++;
                
			// Then load the next loader in.
            loadNext();
        }

		/**
         * Loads the next loader.
         */
        protected function loadNext():void 
		{
            if(this.queue.length > this.active && running) 
			{	
				// Instance of the current loader.
                var loader:AbstractLoader = AbstractLoader(this.queue[ this.active ]);
                loader.addEventListener(Event.COMPLETE, onLoaded);
                loader.load();
			}
            else loadEnd();
        }

        /**
         * Dispatches the open event and sets the run state to true.
         */
        protected function loadStart():void 
		{
            this.run = true;
            dispatchEvent(new Event(Event.OPEN));
        }

        /**
         * Dispatches the complete event and sets the run state to false.
         */
        protected function loadEnd():void 
		{
			this.run = false;
            dispatchEvent(new Event(Event.COMPLETE));
        }
		
		/**
         * Returns the array of the loaders.
         */
        public function get loaders():Array 
		{
            return this.queue;
        }

        /**
         * Returns true when the queue loader is running.
         */
        public function get running():Boolean 
		{
            return this.run;
        }
    }
}